/*
 * @Author: mat
 * @Date: 2020-04-01 15:45:33
 * @LastEditTime: 2020-05-19 15:36:41
 * @LastEditors: Please set LastEditors
 * @Description: 基于Iexplorer二次开发的拓展方法
 * @FilePath: \vue-cesium-template\src\utils\earth.js
 */

/* eslint-disable*/
import axios from "axios";
import store from "../store";
import { debounce, throttle, simpleThrottle } from "./utils.js";
class Earth {
    constructor() {
        this.viewer = {};
        this.baseImageLayer = {};
        this.localImageLayer = {};
        this.baseImageLayerUrl =
            "http://mt1.google.cn/vt/lyrs=s&hl=zh-CN&x={x}&y={y}&z={z}&s=Gali";
        this.terrainLayerUrl =
            config.icenter_url +
            "/tilecache/service/terrain/Global_DEM-TERRAIN-4326";
        this.group = {};
        this.modelGraphic = null;
        this.dataJson = {};
        this.TargetHistory = {};
        this.timeout = null;
    }
    init(earthID) {
        // 初始化地球
        this.viewer = new GV.GeoCanvas(earthID, {
            shouldAnimate: true, //启用动画
            timeline: true,
            animation: true,
            baseLayerPicker: false,
            skyBox: new Cesium.SkyBox({
                sources: {
                    positiveX: "images/SkyBox/mx.jpg",
                    negativeX: "images/SkyBox/mx.jpg",
                    positiveY: "images/SkyBox/py.jpg",
                    negativeY: "images/SkyBox/my.jpg",
                    positiveZ: "images/SkyBox/pz.jpg",
                    negativeZ: "images/SkyBox/mz.jpg"
                }
            })
        });

        var options = {};
        // 用于在使用重置导航重置地图视图时设置默认视图控制。接受的值是Cesium.Cartographic 和Cesium.Rectangle.
        options.defaultResetView = Cesium.Cartographic.fromDegrees(
            110,
            30,
            2000000
        );
        // 用于启用或禁用罗盘。true是启用罗盘，false是禁用罗盘。默认值为true。如果将选项设置为false，则罗盘将不会添加到地图中。
        options.enableCompass = true;
        // 用于启用或禁用缩放控件。true是启用，false是禁用。默认值为true。如果将选项设置为false，则缩放控件 将不会添加到地图中。
        options.enableZoomControls = true;
        // 用于启用或禁用距离图例。true是启用，false是禁用。默认值为true。如果将选项设置为false，距离图例将不会添加到地图中。
        options.enableDistanceLegend = true;
        // 用于启用或禁用指南针外环。true是启用，false是禁用。默认值为true。如果将选项设置为false，则该环将可见但无效。
        options.enableCompassOuterRing = true;
        options.mapMode2D = Cesium.MapMode2D.ROTATE;

        this.viewer.extend(Cesium.viewerCesiumNavigationMixin, options);

        // this.viewer.scene.morphTo2D(0); //切换二维
        this.viewer.scene.debugShowFramesPerSecond = true; //显示帧率
        this.setGlobalHandler();
        this.changeTimeLine();
        this.dynamicChangeTime();
        let that = this;
        // 全球影像
        this.baseImageLayer = this.viewer.imageryLayers.addImageryProvider(
            new Cesium.UrlTemplateImageryProvider({
                url: that.baseImageLayerUrl
            })
        );

        // this.IEflyTo(
        //   {
        //     lon: 118.89758500436089,
        //     lat: 33.052020819327375,
        //     alt: 590123.0816038932,
        //     heading: 358.4052051397172,
        //     pitch: -58.624731557160786,
        //     roll: 359.999937758499
        //   },
        //   3,
        //   1000
        // )
    }
    // 设置cesium全局事件
    setGlobalHandler() {
        let that = this;
        // 注册cesium全局事件
        const leftClickHandler = new Cesium.ScreenSpaceEventHandler(
            that.viewer.canvas
        );
        const mousemoveHandler = new Cesium.ScreenSpaceEventHandler(
            that.viewer.canvas
        );
        leftClickHandler.setInputAction(function(movement) {
            const pickedObject = that.viewer.scene.pick(movement.position);
            console.log(that.cartesian2ToCartographic(movement.position));
            // ie中通过GraphicLayer加载的对象可以通过该方法拾取
            // const pickedObject = that.viewer.graphicLayer.pickByCoordinate(movement.position.x, movement.position.y)
            if (
                Cesium.defined(pickedObject) &&
                Cesium.defined(pickedObject.id) &&
                typeof pickedObject.id.leftClick === "function"
            ) {
                pickedObject.id.leftClick(pickedObject.id);
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

        var debounceFunc = debounce(that.mouseMoveEvent, 1000, true, that);
        var throttleFunc = throttle(that.mouseMoveEvent, 100, that, {
            leading: false
        });
        var simpleThrottleFunc = simpleThrottle(that.mouseMoveEvent, 100, that);
        mousemoveHandler.setInputAction(function mouseMove(movement) {
            // debounceFunc(movement)
            // throttleFunc(movement)
            simpleThrottleFunc(movement);
            // that.mouseMoveEvent(movement)
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    }
    // cesium鼠标浮动事件
    mouseMoveEvent(movement) {
        const pickedObject = this.viewer.scene.pick(movement.endPosition);
        const iepickedObject = this.viewer.graphicLayer.pickByCoordinate(
            movement.endPosition.x,
            movement.endPosition.y
        );
        // entity 如果包含属性cursor，鼠标浮动时变小手
        if (
            (Cesium.defined(pickedObject) &&
                Cesium.defined(pickedObject.id) &&
                pickedObject.id.cursor === true) ||
            (iepickedObject && iepickedObject.cursor)
        ) {
            this.viewer.canvas.style.cursor = "pointer";
        } else {
            this.viewer.canvas.style.cursor = "default";
        }
        // 如果为该entity添加了鼠标浮动事件，调用该方法
        // 所有infoBox都绑定 vuex 中的infoBoxShow，在鼠标浮动时，先将其设置为false
        store.dispatch("layerManage/setInfoBoxShowFun", false);
        if (
            Cesium.defined(pickedObject) &&
            Cesium.defined(pickedObject.id) &&
            typeof pickedObject.id.mouseMove === "function"
        ) {
            pickedObject.id.mouseMove(pickedObject.id, movement.endPosition);
        }
        // iepickedObject 的判断
        if (
            iepickedObject &&
            iepickedObject.mouseMove &&
            typeof iepickedObject.mouseMove === "function"
        ) {
            iepickedObject.mouseMove(iepickedObject, movement.endPosition);
        }
    }
    // 改变原生的Animation日期格式，Timeline 的时间格式在源码中修改
    changeTimeLine() {
        var date = new Date();
        // 可返回格林威治时间和本地时间之间的时差
        var h = 0 - date.getTimezoneOffset();
        this.viewer.animation.viewModel.timeFormatter = function(
            date,
            viewModel
        ) {
            // 重新构造一个当前系统时间的儒略日
            var dateZone = Cesium.JulianDate.addMinutes(
                date,
                h,
                new Cesium.JulianDate()
            );
            var gregorianDate = Cesium.JulianDate.toGregorianDate(dateZone);
            var millisecond = Math.round(gregorianDate.millisecond);
            // 倍速是否小于 1, 小于 1 则显示毫秒级
            if (Math.abs(viewModel._clockViewModel.multiplier) < 1) {
                return Cesium.sprintf(
                    "%02d:%02d:%02d.%03d",
                    gregorianDate.hour,
                    gregorianDate.minute,
                    gregorianDate.second,
                    gregorianDate.millisecond
                );
            }
            return Cesium.sprintf(
                "%02d:%02d:%02d",
                gregorianDate.hour,
                gregorianDate.minute,
                gregorianDate.second
            );
        };
        // 设置日期
        this.viewer.animation.viewModel.dateFormatter = function(
            date,
            viewModel
        ) {
            var dateZone = Cesium.JulianDate.addMinutes(
                date,
                h,
                new Cesium.JulianDate()
            );
            var gregorianDate = Cesium.JulianDate.toGregorianDate(dateZone);
            // 设置格式为 xx/xx/xx, 格式可自定义为任意你想要的
            return Cesium.sprintf(
                "%4d/%02d/%02d",
                gregorianDate.year,
                gregorianDate.month,
                gregorianDate.day
            );
        };
    }
    dynamicChangeTime() {
        var that = this;
        var startTime = this.viewer.clock.startTime;
        var stopTime = this.viewer.clock.stopTime;
        function tick() {
            var currentTime = Cesium.JulianDate.clone(
                that.viewer.clock.currentTime
            );
            if (Cesium.JulianDate.greaterThan(currentTime, stopTime)) {
                startTime = Cesium.JulianDate.addDays(
                    startTime,
                    1.0,
                    startTime
                );
                stopTime = Cesium.JulianDate.addDays(stopTime, 1.0, stopTime);
                that.viewer.timeline.zoomTo(startTime, stopTime);
            }
            Cesium.requestAnimationFrame(tick);
        }
        Cesium.requestAnimationFrame(tick);
    }
    // 飞行
    flyto(lat, lon, hight) {
        this.viewer.camera.flyTo({
            destination: Cesium.Cartesian3.fromDegrees(lat, lon, hight),
            orientation: {
                // direction: new Cesium.Cartesian3(0.04231243104240401,0.20123236049443421,0.97862924300734),
                // up: new Cesium.Cartesian3(0.47934589305293746,0.8553216253114552,0.1966022179118339)
                // heading : Cesium.Math.toRadians(0), // 方向
                // pitch : Cesium.Math.toRadians(-90.0),// 倾斜角度
                // roll : 0
            }
        });
    }
    /**
     * @description: iexplorer 中飞行的方法，使用earth.iCamera.viewPoint 可以获取当前position
     * @param {position: 位置对象; duration: 飞行持续时间; delayTime: 延时时间}
     * @return:
     */
    IEflyTo(position, duration = 3, delayTime = 0) {
        let that = this;
        if (position) {
            setTimeout(() => {
                that.viewer.iCamera.flyTo(
                    {
                        lon: position.lon,
                        lat: position.lat,
                        alt: position.alt,
                        heading: position.heading,
                        pitch: position.pitch,
                        roll: position.roll
                    },
                    duration
                );
            }, delayTime);
        }
    }
    // 切换底图
    changeBaseLayer(option) {
        if (this.baseImageLayer) {
            this.viewer.imageryLayers.remove(this.baseImageLayer);
            this.baseImageLayer = null;
        }
        this.baseImageLayer = this.addLayer(option);
        this.viewer.imageryLayers.lowerToBottom(this.baseImageLayer);
        this.viewer.imageryLayers.raise(this.baseImageLayer);
    }
    //添加图层
    addLayer(option) {
        switch (option.type) {
            case "tms":
                return this.addTMSLayer(option);
                break;
            case "wmts":
                return this.addWMTSLayer(option);
                break;
            case "urlTemp":
                return this.addURLTempLayer(option);
                break;
            default:
                break;
        }
    }
    // 指定url的format模版添加图层
    addURLTempLayer(option) {
        let _layer = this.viewer.imageryLayers.addImageryProvider(
            new Cesium.UrlTemplateImageryProvider({
                url: option.url ? option.url : ""
            })
        );
        _layer.name = option.name ? option.name : "";
        return _layer;
    }

    // TMS
    addTMSLayer(option) {
        let _layer = this.viewer.imageryLayers.addImageryProvider(
            new Cesium.createTileMapServiceImageryProvider({
                url: option.url ? option.url : "",
                tilingScheme: new Cesium.GeographicTilingScheme() //地图平铺方案，前面墨卡托，后面平铺 WebMercatorTilingScheme  GeographicTilingScheme
            })
        );
        _layer.name = option.name ? option.name : "";
        return _layer;
    }
    // MWTS
    addWMTSLayer(option) {
        let _layer = this.viewer.imageryLayers.addImageryProvider(
            new Cesium.WebMapTileServiceImageryProvider({
                url: option.url ? option.url : "",
                layer: option.layer ? option.layer : "",
                style: "default",
                format: option.format ? option.format : "image/jpeg",
                tileMatrixSetID: option.tileMatrixSetID
                    ? option.tileMatrixSetID
                    : "EPSG:4326"
            })
        );
        _layer.name = option.name ? option.name : "";
        return _layer;
    }
    // 管道
    addToolbarButton() {
        let that = this;
        that.group = new GV.GraphicGroup();
        that.viewer.graphicLayer.add(that.group);
        // 管道
        let volumePolylineGraphic = new GV.VolumePolylineGraphic({
            visible: true,
            positions: [
                new GV.GeoPoint(0, 0, 100000),
                new GV.GeoPoint(20, 10, 10000)
            ],
            shape: GV.GeoPoint.unpackArray([
                [0, -50000],
                [15450.84971874737, -47552.82581475768],
                [29389.262614623658, -40450.84971874737],
                [40450.84971874737, -29389.26261462365],
                [47552.82581475768, -15450.849718747373],
                [50000, 8.040613248383182e-12],
                [47552.82581475768, 15450.849718747379],
                [40450.84971874737, 29389.26261462365],
                [29389.26261462366, 40450.84971874737],
                [15450.849718747357, 47552.825814757685],
                [-1.6081226496766365e-11, 50000],
                [-15450.849718747386, 47552.82581475768],
                [-29389.26261462367, 40450.84971874736],
                [-40450.84971874737, 29389.26261462366],
                [-47552.82581475768, 15450.849718747379],
                [-50000, 9.184850993605149e-12],
                [-47552.825814757685, -15450.849718747362],
                [-40450.84971874735, -29389.262614623683],
                [-20336.83215379001, -45677.27288213005],
                [-5226.423163382671, -49726.09476841366]
            ]),
            cornerType: "rounded",
            fill: true,
            outline: false,
            outlineWidth: 1,
            outlineColor: "#40B4DB",
            color: "rgba(77, 216, 255, 0.4)"
        });
        that.group.add(volumePolylineGraphic);
    }
    // 移除管道
    removeToolbarButton() {
        this.group.clear();
    }

    /**
     * 飞机
     * @param {*} status 飞机状态
     */
    addPlanePath(geoPoints, status) {
        this.removePlane();
        let that = this;
        // const start = new GV.GeoPoint(0, 0, 100000)
        // const end = new GV.GeoPoint(20, 10, 10000)
        const factor = 30;
        //飞机
        that.modelGraphic = new GV.ModelGraphic({
            url: "./dist/resources/model/satelliteDemo/Cesium_Air.glb",
            position: geoPoints[0],
            scale: 70
        });
        that.viewer.graphicLayer.add(that.modelGraphic);
        //计算差分点以及时间
        // const positions = GV.Calculate.getParabola(start, end, factor, 40, that.viewer)
        // const positions = GV.Calculate.getBezier(geoPoints)
        const positionsInfo = [];
        let time = 0;
        for (const point of geoPoints) {
            positionsInfo.push({ point: point, time: time });
            time += 5;
        }
        const path = new GV.Path(that.viewer);
        path.pathPositions = positionsInfo;
        //回调函数根据时间返回对应的主模型的位置和姿态
        path.callback = (position, heading, pitch, roll) => {
            that.modelGraphic.position = position;
            that.modelGraphic.heading = heading;
            that.modelGraphic.pitch = pitch;
            that.modelGraphic.roll = roll;
        };
        path.start();
        //  开始/结束动画
        // if (status) {
        //   path.start()
        // } else {
        //   path.stop()
        // }
    }
    // 移除模型
    removePlane() {
        if (!this.modelGraphic) return false;
        this.viewer.graphicLayer.remove(this.modelGraphic);
    }
    /**
     * @description: 添加Kml数据
     * @param
     */
    addKmlDataSource(url, name, color, type, event) {
        let that = this;
        Cesium.KmlDataSource.load(url, {
            camera: that.viewer.scene.camera,
            canvas: that.viewer.scene.canvas
        }).then(function(dataSource) {
            let entities = dataSource.entities.values;
            for (let i = 0; i < entities.length; ++i) {
                // let positions = entities[i].polyline.hierarchy._value.positions
                // entities[i].polygon = undefined
                // entities[i].polyline = new Cesium.PolylineGraphics({
                //   positions: [...positions, positions[0]],
                //   width: 3,
                //   material: Cesium.Color.fromCssColorString('rgb(255,0,0)'),
                //   clampToGround: true
                // })
                // if (type && event) {
                //   entities[i][type] = event
                // }
                // entities[i].name = name
                entities[i].cursor = true;
            }

            that.dataJson[url] = dataSource;
            that.viewer.dataSources.add(dataSource);
            // that.viewer.zoomTo(dataSource)
        });
    }
    addTriangleMeshGraphic() {
        let data = {
            points: [
                100,
                37.26485134792725,
                0,
                118.3285382401569,
                37.08646598318436,
                0,
                118.7172125631428,
                37.20312661929784,
                0,
                118.5539223077147,
                37.35018476556944,
                0,
                118.7172125631428,
                37.20312661929784,
                10000,
                118.5539223077147,
                37.35018476556944,
                10000
            ],
            indices: [0, 1, 2, 3, 4, 5]
        };
        let opt = new GV.TriangleMeshGraphicOpt();
        opt.color = "#00CED1";
        opt.dataSource = { points: data.points, indices: data.indices };
        let TMesh = new GV.TriangleMeshGraphic(opt);
        let obj = this.viewer.graphicLayer.add(TMesh);
        // this.flyto(118.279864040361)
    }
    // 世界坐标转地理坐标  cartesian3 转 经纬度
    cartesian3ToCartographic(cartesian3) {
        var car = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(
            cartesian3
        );
        var lon = Cesium.Math.toDegrees(car.longitude);
        var lat = Cesium.Math.toDegrees(car.latitude);
        return [lon, lat];
    }
    // 屏幕坐标转地理坐标  cartesian2 -> cartesian3 -> 经纬度
    cartesian2ToCartographic(cartesian2) {
        let cartesian3 = this.viewer.scene.globe.pick(
            this.viewer.camera.getPickRay(cartesian2),
            this.viewer.scene
        );
        return this.cartesian3ToCartographic(cartesian3);
    }
}
export default Earth;
